/*
 * edbd_util.c - edbd utility functions
 * Clunix, glory@clunix.com, yjlee@clunix.com, 2001.11.7.
 *
 * Copyright (c) 2001 by Clunix Inc. All Rights Reserved.
 */

#include "config.h"

#ifndef WIN32
#include <fcntl.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/wait.h>
#else

#endif

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include "edbd.h"
#include "edb_proto.h"
#include "edbroot.h"

edb_err_t
oct_to_file(const char *basedir, sr_t *sr_oct, ECMBOOL overwrite)
{
	const char	*filename, *filepath;
	int	fd;
	ECMBOOL	res = ECM_FALSE;

	filename = sr_get_name(sr_oct);
	if (filename == NULL)
		return ECM_FALSE;
	filepath = ecm_gen_path(basedir, filename, NULL);
	if (ecm_access(filepath, ECM_F_OK) && !overwrite) {
		ecm_free(filepath);
		return -ERR_EDB_EXIST;
	}
	fd = ecm_open(filepath, ECM_O_WRONLY | ECM_O_CREAT | ECM_O_TRUNC, ECM_P_RWUSR);
	if (fd >= 0) {
		ecm_size_t	bufsize, size;
		char	*data;
		bufsize = size = sr_get_oct_size(sr_oct);
		data = sr_get_oct_data(sr_oct);
		if (ecm_write(fd, data, &bufsize) && bufsize == size)
			res = ECM_TRUE;
		ecm_close(fd);
	}
	ecm_free(filepath);
	return res;
}

sr_t *
file_to_oct(const char *cfilepath)
{
	sr_t	*sr_oct = NULL;
	char	*filepath = ecm_strdup(cfilepath);
	const char	*filename;
	int	fd;

	filename = ecm_basename(filepath);
	if (filename == NULL) {
		ecm_free(filepath);
		return NULL;
	}
	fd = ecm_open(filepath, ECM_O_RDONLY);
	if (fd >= 0) {
		ecm_size_t	size;

		if (ecm_filesize(fd, &size)) {
			char	*data;
			ecm_size_t	bufsize;

			data = ecm_malloc(size);
			bufsize = size;
			if (ecm_read(fd, data, &bufsize) == size) {
				sr_oct = sr_create(ST_OCT);
				sr_set_val(sr_oct, sr_val_oct(size, data));
				sr_set_name(sr_oct, filename);
			}
			else
				ecm_free(data);
		}
		ecm_close(fd);
	}
	ecm_free(filepath);
	return sr_oct;
}

ECM_INLINE ECMBOOL
is_attr_modifiable(const sr_t *sr)
{
	ECMASSERT(edbroot_is_ontree(sr));

	if (eds_get_attr_system(sr_get_real(sr)) & ST_ATTR_SYSTEM_MODIFIABLE)
		return ECM_TRUE;
	return ECM_FALSE;
}

ECM_INLINE ECMBOOL
is_attr_volatile(const sr_t *sr)
{
	ECMASSERT(edbroot_is_ontree(sr));

	if (eds_get_attr_system(sr_get_real(sr)) & ST_ATTR_SYSTEM_VOLATILE)
		return ECM_TRUE;
	return ECM_FALSE;
}

ECM_INLINE ECMBOOL
is_attr_owner_xid(xid_t owner)
{
	if (owner == ST_XID_MODIFIER)
		return ECM_TRUE;

	if (owner == self_node_xid ||
	    owner == ST_XID_SELF ||
	    ((owner == ST_XID_MASTER || owner == 0) && IS_MASTER()))
		return ECM_TRUE;
	return ECM_FALSE;
}

ECM_INLINE ECMBOOL
is_attr_owner(const sr_t *sr)
{
	xid_t		owner;
	ecm_uint32	attr_update;

	ECMASSERT(edbroot_is_ontree(sr));

	owner = eds_get_owner(sr_get_real(sr));
	attr_update = eds_get_attr_update(sr_get_real(sr));

	if (attr_update == ST_ATTR_UPDATE_PRIVATE)
		return ECM_TRUE;
	return is_attr_owner_xid(owner);
}

ECM_INLINE ECMBOOL
is_attr_owner_master(const sr_t *sr)
{
	xid_t		owner;

	ECMASSERT(edbroot_is_ontree(sr));

	owner = eds_get_owner(sr_get_real(sr));
	return (owner == ST_XID_MASTER);
}

ECM_INLINE ECMBOOL
is_attr_owner_modifier(const sr_t *sr)
{
	xid_t		owner;

	ECMASSERT(edbroot_is_ontree(sr));

	owner = eds_get_owner(sr_get_real(sr));

	return (owner == ST_XID_MODIFIER);
}

ECM_INLINE ECMBOOL
is_attr_update_private(const sr_t *sr)
{
	ECMASSERT(edbroot_is_ontree(sr));

	if (eds_get_attr_update(sr_get_real(sr)) == ST_ATTR_UPDATE_PRIVATE)
		return ECM_TRUE;
	return ECM_FALSE;
}

ECM_INLINE ECMBOOL
is_attr_update_instant(const sr_t *sr)
{
	ECMASSERT(edbroot_is_ontree(sr));

	if (eds_get_attr_update(sr_get_real(sr)) == ST_ATTR_UPDATE_INSTANT)
		return ECM_TRUE;
	return ECM_FALSE;
}

ECM_INLINE ECMBOOL
is_attr_fetch_normal(const sr_t *sr)
{
	ECMASSERT(edbroot_is_ontree(sr));

	if (eds_get_attr_fetch(sr_get_real(sr)) & ST_ATTR_FETCH_NORMAL)
		return ECM_TRUE;
	return ECM_FALSE;
}

ECM_INLINE ECMBOOL
is_attr_fetch_ondemand(const sr_t *sr)
{
	ECMASSERT(edbroot_is_ontree(sr));

	if (eds_get_attr_fetch(sr_get_real(sr)) & ST_ATTR_FETCH_ONDEMAND)
		return ECM_TRUE;
	return ECM_FALSE;
}

ECM_INLINE xid_t
xidstr_to_xid(const char *xidstr)
{
	sr_val_t	xid_val;

	sr_casrv_scan(xidstr, ST_XID, &xid_val);
	ecm_free(xidstr);
	return xid_val.lval;
}

ECM_INLINE ECMBOOL
ndname_to_xid(const char *c_ndname, xid_t *pxid)
{
	sr_val_t	val_xid;
	char	*ndname;

	ecm_asprintf(&ndname, "#%s", c_ndname);
	if (!sr_asrv_scan(ndname, ST_XID, &val_xid)) {
		ecm_free(ndname);
		return ECM_FALSE;
	}
	*pxid = val_xid.lval;
	ecm_free(ndname);
	return ECM_TRUE;
}

ECM_INLINE void
ndid_to_xid(ebc_ndid_t ndid, xid_t *pxid)
{
	*pxid = (xid_t)((ecm_uint32)ndid | ST_XID_NORMAL_MASK);
}

ECM_INLINE sr_t *
find_sr_from_ptrs(sr_t *sr_ptrs, const char *name)
{
	sr_t	*sr, *sr_ptr;

	SR_FOREACH_CHILD(sr_ptrs, NULL, sr_ptr) {
		sr = sr_get_ptr(sr_ptr);
		if (sr && ecm_strcmp(sr->name, name) == 0)
			return sr;
	}
	return NULL;
}

static sr_walk_res_t
check_HMS_empty(sr_t **psr, ecm_ptr_t ctx)
{
	if (!tree_is_valid(*psr))
		return SR_WALK_PRUNE;
	if (sr_get_member_type(*psr) == ST_NULL ||
	    edbroot_empty(*psr))
		return SR_WALK_OK;
	return SR_WALK_FAILED;
}

ECM_INLINE ECMBOOL
has_empty_HMS(const sr_t *sr)
{
	if (!tree_lock(sr, RECUR_SH_LOCK))
		return ECM_TRUE;
	if (!sr_walk((sr_t *)sr, check_HMS_empty, NULL, SR_RECUR | SR_NO_DEREF)) {
		tree_unlock(sr, RECUR_SH_LOCK);
		return ECM_FALSE;
	}
	tree_unlock(sr, RECUR_SH_LOCK);
	return ECM_TRUE;
}
